﻿#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

// Disable security warnings
#pragma warning(disable: 4996)

// Function declarations
void ShowHelp();
bool ParseMacAddress(const char* input, unsigned char* mac);
bool SendWakeOnLanPacket(const unsigned char* mac, const char* broadcastAddr, int port);

int main(int argc, char* argv[])
{
    // No parameters, show help
    if (argc == 1)
    {
        ShowHelp();
        return 0;
    }

    // Default values
    char broadcastAddr[20] = "255.255.255.255";
    int port = 50000;
    unsigned char mac[6] = { 0 };
    bool hasMac = false;

    // Parse command line arguments
    for (int i = 1; i < argc; i++)
    {
        if (strcmp(argv[i], "-b") == 0 && i + 1 < argc)
        {
            strcpy(broadcastAddr, argv[i + 1]);
            i++;
        }
        else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc)
        {
            port = atoi(argv[i + 1]);
            i++;
        }
        else
        {
            // Try to parse as MAC address
            if (!hasMac && ParseMacAddress(argv[i], mac))
            {
                hasMac = true;
            }
            else
            {
                printf("Invalid parameter: %s\n\n", argv[i]);
                ShowHelp();
                return 1;
            }
        }
    }

    // Check if MAC address was provided
    if (!hasMac)
    {
        printf("No MAC address provided\n\n");
        ShowHelp();
        return 1;
    }

    // Send wake-on-lan packet
    if (SendWakeOnLanPacket(mac, broadcastAddr, port))
    {
        printf("WOL packet sent to MAC address: %02X:%02X:%02X:%02X:%02X:%02X, broadcast address: %s, port: %d\n",
            mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], broadcastAddr, port);
        return 0;
    }
    else
    {
        printf("Failed to send wake-on-lan packet\n");
        return 1;
    }
}

// Show help information
void ShowHelp()
{
    printf("Wake-on-LAN Tool (WOL)\n");
    printf("Usage: wolcmd MAC_ADDRESS [-b BROADCAST_ADDRESS] [-p PORT]\n\n");
    printf("Parameters:\n");
    printf("  MAC_ADDRESS     Required, supported formats: 00:11:22:33:44:55, 00-11-22-33-44-55 or 001122334455\n");
    printf("  -b              Optional, specify broadcast address, default is 255.255.255.255\n");
    printf("  -p              Optional, specify port number, default is 50000\n\n");
    printf("Examples:\n");
    printf("  wolcmd 00:11:22:33:44:55\n");
    printf("  wolcmd 00-11-22-33-44-55 -b 192.168.1.255 -p 7\n");
}

// Parse MAC address
bool ParseMacAddress(const char* input, unsigned char* mac)
{
    int len = strlen(input);
    int count = 0;
    unsigned int value = 0;
    bool found = false;
    int digitCount = 0;

    // Parse MAC address
    for (int i = 0; i < len && count < 6; i++)
    {
        if (isxdigit(input[i]))
        {
            // Convert hexadecimal character to value
            if (isdigit(input[i]))
                value = value * 16 + (input[i] - '0');
            else
                value = value * 16 + (tolower(input[i]) - 'a' + 10);
            found = true;
            digitCount++;

            // For non-delimited format, save a byte every 2 hex digits
            if (digitCount == 2 && input[i + 1] != ':' && input[i + 1] != '-')
            {
                mac[count++] = (unsigned char)value;
                value = 0;
                found = false;
                digitCount = 0;
            }
        }
        else if (input[i] == ':' || input[i] == '-')
        {
            // Handle separators
            if (found && count < 6)
            {
                mac[count++] = (unsigned char)value;
                value = 0;
                found = false;
                digitCount = 0;
            }
            else
            {
                return false;
            }
        }
        else
        {
            // Invalid character
            return false;
        }
    }

    // Process the last byte
    if (found && count < 6)
    {
        mac[count++] = (unsigned char)value;
    }

    // Check if 6 bytes were parsed
    return (count == 6);
}

// Send WOL packet
bool SendWakeOnLanPacket(const unsigned char* mac, const char* broadcastAddr, int port)
{
    WSADATA wsaData;
    SOCKET sock;
    struct sockaddr_in addr;
    unsigned char packet[102] = { 0 };

    // Initialize Winsock
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        return false;
    }

    // Create UDP socket
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == INVALID_SOCKET)
    {
        WSACleanup();
        return false;
    }

    // Set socket option to broadcast mode
    int optval = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&optval, sizeof(optval)) != 0)
    {
        closesocket(sock);
        WSACleanup();
        return false;
    }

    // Set broadcast address and port
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(broadcastAddr);
    addr.sin_port = htons(port);

    // Construct WOL packet
    // First 6 bytes are 0xFF
    for (int i = 0; i < 6; i++)
    {
        packet[i] = 0xFF;
    }

    // Then repeat MAC address 16 times
    for (int i = 0; i < 16; i++)
    {
        memcpy(&packet[6 + i * 6], mac, 6);
    }

    // Send packet
    int result = sendto(sock, (char*)packet, sizeof(packet), 0, (struct sockaddr*)&addr, sizeof(addr));

    // Cleanup resources
    closesocket(sock);
    WSACleanup();

    // Check send result
    return (result != SOCKET_ERROR);
}